package com.mxjsxz.demo.controller.composite;

import com.mxjsxz.demo.constants.AiTongueConstant;
import com.mxjsxz.demo.model.form.TongueInquiryAnswerForm;
import com.mxjsxz.demo.model.form.composite.CompositePreTaskSecretForm;
import com.mxjsxz.demo.model.form.composite.CompositeTaskSecretForm;
import com.mxjsxz.demo.model.vo.ResultVO;
import com.mxjsxz.demo.model.vo.ReturnVO;
import com.mxjsxz.demo.model.vo.composite.CompositeReturnVO;
import com.mxjsxz.demo.properties.AiTongueProperties;
import com.mxjsxz.demo.service.IRestTemplateService;
import com.mxjsxz.demo.utils.AesSimpleUtil;
import com.mxjsxz.demo.utils.JsonUtil;
import com.mxjsxz.demo.utils.RsaSimpleUtil;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import static com.mxjsxz.demo.constants.AiTongueConstant.SUCCESS;

/**
 * 中医辨识 API（融合版）
 *
 * @author xuwenbing
 * @date 2023-10-10
 */
@RestController
@RequestMapping("composite")
public class DemoCompositeController {
    private final Logger log = LoggerFactory.getLogger(DemoCompositeController.class);
    private final AiTongueProperties aiTongueProperties;
    private final IRestTemplateService restTemplateService;


    @Autowired
    public DemoCompositeController(AiTongueProperties aiTongueProperties, IRestTemplateService restTemplateService) {
        this.aiTongueProperties = aiTongueProperties;
        this.restTemplateService = restTemplateService;
    }

    /**
     * 阶段一：验证舌象
     *
     * @param outId           第三方单据id，形如：“20221025001”
     * @param returnUrlPrefix 结果接收地址前缀，形如：“http://192.168.1.43:8080”，然后形成完成结果接收地址为：”http://192.168.1.43:8080/composite/resultReturn“
     * @return
     * @throws Exception
     */
    @PostMapping("pre")
    public String pre(@RequestParam String outId, @RequestParam String returnUrlPrefix) throws Exception {
        if (StringUtils.isAnyBlank(outId, returnUrlPrefix)) {
            return AiTongueConstant.ERROR;
        }
        // 1.获取accesstoken
        String accesstoken = this.getAccessToken(aiTongueProperties.getDevId(), aiTongueProperties.getDevSecret());
        if (StringUtils.isBlank(accesstoken)) {
            return AiTongueConstant.ERROR;
        }
        Map<String, String> headers = new HashMap<>();
        headers.put("Authorization", "Bearer " + accesstoken);

        // 2.准备待检测的数据：第三方单据id、舌面图片、舌下图片、正面部、左侧面部、右侧面部和结果接收地址
        CompositePreTaskSecretForm form = new CompositePreTaskSecretForm();
        form.setReturnUrl(returnUrlPrefix + "/composite/resultReturn");
        form.setImageType((short) 1);
        // imageType=2时，打开以下注释
//        form.setTongueImgUrl("https://www.ai-tongue.com/h5/static/img/back1.136f219.png");
//        form.setTongueBackImgUrl("https://www.ai-tongue.com/h5/static/img/back2.c8e89f9.png");
//        form.setFaceImgUrl("https://www.ai-tongue.com/h5/static/img/back3.0aab462.png");
//        form.setFaceLeftImgUrl("https://www.ai-tongue.com/h5/static/img/back4.536cd76.png");
//        form.setFaceRightImgUrl("https://www.ai-tongue.com/h5/static/img/back5.2daaef7.png");


        // 3.加密和签名数据
        String signature = RsaSimpleUtil.sign(outId, aiTongueProperties.getDevRsaPrivateKey());
        String sourceData = JsonUtil.toJson(form);
        String encryptData = AesSimpleUtil.encrypt(sourceData, aiTongueProperties.getAesKey());

        // 4.上传检测
        MultiValueMap<String, Object> params = new LinkedMultiValueMap<>();
        params.add("outId", outId);
        params.add("signature", signature);
        params.add("encryptData", encryptData);
        // imageType=1时，打开以下注释
        params.add("tongueImg", restTemplateService.getClassPathFileSystemResource("static/tongue.jpg"));
        params.add("tongueBackImg", restTemplateService.getClassPathFileSystemResource("static/tongueBack.jpg"));
        params.add("faceImg", restTemplateService.getClassPathFileSystemResource("static/face_main.jpg"));
        params.add("faceLeftImg", restTemplateService.getClassPathFileSystemResource("static/face_left.png"));
        params.add("faceRightImg", restTemplateService.getClassPathFileSystemResource("static/face_right.png"));

        // 当resultVO.code=0表示上传成功：
        // （1）检测的结果会回传到您设置的returnUrl上
        ResultVO resultVO = restTemplateService.postForObject(aiTongueProperties.getCompositePreTaskUrl(),
                headers, params, ResultVO.class);
        log.info("pre:{}", JsonUtil.toJson(resultVO));
        return AiTongueConstant.OK;
    }

    /**
     * 阶段二：1、确认提交检测
     *
     * @return
     */
    @PostMapping("do")
    public String dO(@RequestParam String outId) throws Exception {
        if (StringUtils.isAnyBlank(outId)) {
            return AiTongueConstant.ERROR;
        }
        // 1.获取accesstoken
        String accesstoken = this.getAccessToken(aiTongueProperties.getDevId(), aiTongueProperties.getDevSecret());
        if (StringUtils.isBlank(accesstoken)) {
            return AiTongueConstant.ERROR;
        }
        Map<String, String> headers = new HashMap<>();
        headers.put("Authorization", "Bearer " + accesstoken);

        // 2.准备待检测的数据：第三方单据id、舌面图片、舌下图片、年龄、性别和结果接收地址
        CompositeTaskSecretForm form = new CompositeTaskSecretForm();
        form.setAge(20);
        form.setSex((short) 1);
        form.setHeight(BigDecimal.valueOf(180.0));
        form.setWeight(BigDecimal.valueOf(80.0));
        form.setDiseaseCode("C00.D00");
        form.setRequireInquiry(true);

        // 3.加密和签名数据
        String signature = RsaSimpleUtil.sign(outId, aiTongueProperties.getDevRsaPrivateKey());
        String sourceData = JsonUtil.toJson(form);
        String encryptData = AesSimpleUtil.encrypt(sourceData, aiTongueProperties.getAesKey());

        // 4.上传检测
        MultiValueMap<String, Object> params = new LinkedMultiValueMap<>();
        params.add("outId", outId);
        params.add("signature", signature);
        params.add("encryptData", encryptData);
        // 当resultVO.code=0表示上传成功：
        // （1）resultVO.data表示预计等待检测时间，
        // （2）检测的结果会回传到您设置的returnUrl上
        ResultVO resultVO = restTemplateService.postForObject(aiTongueProperties.getCompositeDoTaskUrl(),
                headers, params, ResultVO.class);
        log.info("task:{}", JsonUtil.toJson(resultVO));
        return AiTongueConstant.OK;
    }

    /**
     * 阶段二：2、回答问诊问题
     *
     * @return
     */
    @PostMapping("inquiry")
    public String inquiry(@RequestParam String outId) throws Exception {
        if (StringUtils.isAnyBlank(outId)) {
            return AiTongueConstant.ERROR;
        }
        // 1.获取accesstoken
        String accesstoken = this.getAccessToken(aiTongueProperties.getDevId(), aiTongueProperties.getDevSecret());
        if (StringUtils.isBlank(accesstoken)) {
            return AiTongueConstant.ERROR;
        }
        Map<String, String> headers = new HashMap<>();
        headers.put("Authorization", "Bearer " + accesstoken);

        // 2.准备问诊回答数据：第三方单据id和问诊回答数据
        // 务必保证每个问题都有答案，如果用户没有回答则使用默认答案（TongueQuestionVO.defaultOption）
        List<TongueInquiryAnswerForm.InquiryAnswer> inquiryAnswerList = new ArrayList<>();
        inquiryAnswerList.add(new TongueInquiryAnswerForm.InquiryAnswer(1, "是"));
        inquiryAnswerList.add(new TongueInquiryAnswerForm.InquiryAnswer(2, "是"));
        inquiryAnswerList.add(new TongueInquiryAnswerForm.InquiryAnswer(3, "是"));
        inquiryAnswerList.add(new TongueInquiryAnswerForm.InquiryAnswer(4, "是"));
        TongueInquiryAnswerForm inquiryAnswerForm = new TongueInquiryAnswerForm();
        inquiryAnswerForm.setOutId(outId);
        inquiryAnswerForm.setInquiryAnswers(inquiryAnswerList);

        // 3.加密和签名数据
        String signature = RsaSimpleUtil.sign(outId, aiTongueProperties.getDevRsaPrivateKey());
        String sourceData = JsonUtil.toJson(inquiryAnswerForm);
        String encryptData = AesSimpleUtil.encrypt(sourceData, aiTongueProperties.getAesKey());

        // 4.上传问诊答案
        MultiValueMap<String, Object> params = new LinkedMultiValueMap<>();
        params.add("outId", outId);
        params.add("signature", signature);
        params.add("encryptData", encryptData);
        // 当resultVO.code=0表示上传成功：
        // （1）resultVO.data表示预计等待检测时间，
        // （2）检测的结果会回传到您设置的returnUrl上
        ResultVO resultVO = restTemplateService
                .postForObject(aiTongueProperties.getCompositeInquiryTaskUrl(),
                        headers, params, ResultVO.class);
        log.info("inquiry:{}", JsonUtil.toJson(resultVO));
        return AiTongueConstant.OK;
    }


    /**
     * 2、结果接收地址
     *
     * @param returnVO
     * @return
     */
    @PostMapping("resultReturn")
    public String resultReturn(ReturnVO returnVO) throws Exception {
        log.info("composite resultReturn：{}", JsonUtil.toJson(returnVO));
        // 1. 验证签名
        boolean verify = RsaSimpleUtil.verify(returnVO.getOutId(), returnVO.getSignature(), aiTongueProperties.getRsaPublicKey());
        if (verify) {
            // 2. 只有验签通过后才进行业务操作
            // 3. 解密数据
            String decryptData = AesSimpleUtil.decrypt(returnVO.getEncryptData(), aiTongueProperties.getAesKey());
            // 4. decryptData可以转化为TongueReturnVO对象,具体每个字段含义见TongueReturnVO
            CompositeReturnVO vo = JsonUtil.parseObject(decryptData, CompositeReturnVO.class);
            // 其中returnType表示返回结果的类型
            // returnType=0 说明返回的问诊问题列表
            // returnType=1 说明返回的最终体质结果
            // returnType=2 说明返回的失败提示信息
            // returnType=31 预判为合法图片
            // returnType=32 预判为不合法图片
            log.info("composite decryptData：{}", decryptData);
            return SUCCESS;
        }
        log.info("验证签名失败");
        return AiTongueConstant.ERROR;
    }

    /**
     * 获取access_token（获取后建议缓存，一般1小时有效）
     *
     * @param devId
     * @param devSecret
     * @return
     */
    private String getAccessToken(String devId, String devSecret) {
        MultiValueMap<String, Object> params = new LinkedMultiValueMap<>();
        params.add("devid", devId);
        params.add("devsecret", devSecret);
        ResultVO accessTokenResult = restTemplateService.postForObject(aiTongueProperties.getGetTokenUrl(), params, ResultVO.class);
        log.info("access_token result:{}", JsonUtil.toJson(accessTokenResult));
        if (accessTokenResult.getCode() != 0) {
            return null;
        }
        return ((Map) accessTokenResult.getData()).get("access_token").toString();
    }
}
